#include <bits/stdc++.h>
using namespace std;

#define ONLINE_JUDGE

#ifndef ONLINE_JUDGE
#define dbg(x...)                             \
	{                                         \
		cerr << "\033[32;1m" << #x << " -> "; \
		err(x);                               \
	}
void err()
{
	cerr << "\033[39;0m" << endl;
}
template <typename T, typename... A>
void err(T a, A... x)
{
	cerr << a << ' ';
	err(x...);
}
#else
#define dbg(...)
#endif

typedef long long LL;

const int N = 1e3 + 5, M = N * N;

int n, m;

char mp[N][N];

int id[N][N];

namespace shortestpath
{
struct node
{
	int u, dis;
	node(int u = 0, int dis = 0) : u(u), dis(dis)
	{
	}
	bool operator<(const node &other) const
	{
		return dis < other.dis;
	}
};
void go(int s, int dist[], int n, const vector<pair<int, int>> G[])
{
	memset(dist, -1, sizeof(int) * (n+1));
	dist[s] = 0;
	queue<int> Q;
	Q.push(s);
	while (!Q.empty())
	{
		int now = Q.front(); Q.pop();
		for (auto p : G[now])
		{
			int v = p.first;
			if (dist[v] == -1)
			{
				dist[v] = dist[now] + 1;
				Q.push(v);
			}
		}
	}
	// priority_queue<node, vector<node>, greater<node>> pq;
	// pq.emplace(s, 0);
	// while (!pq.empty())
	// {
	// 	auto now = pq.top();
	// 	pq.pop();
	// 	if (dist[now.u] < now.dis)
	// 		continue;
	// 	for (const auto &p : G[now.u])
	// 	{
	// 		int v = p.first, w = p.second;
	// 		if (dist[now.u] + w < dist[v])
	// 		{
	// 			dist[v] = dist[now.u] + w;
	// 			pq.emplace(v, dist[v]);
	// 		}
	// 	}
	// }
}
} // namespace shortestpath

const int dx[4] = {1, -1, 0, 0},
		  dy[4] = {0, 0, 1, -1};

vector<pair<int, int>> G[M];

void addEdge(int u, int v, int w)
{
	G[u].emplace_back(v, m);
}

int main(int argc, char const *argv[])
{
	scanf("%d%d", &n, &m);
	int s = 1, tot = s;
	for (int i = 0; i < n; ++i)
		for (int j = 0; j < m; ++j)
			id[i][j] = ++tot;
	for (int i = 0; i < n; ++i)
	{
		scanf("%s", mp[i]);
		for (int j = 0; j < m; ++j)
		{
			if (mp[i][j] == '#')
			{
				addEdge(s, id[i][j], 0);
			}
			for (int k = 0; k < 4; ++k)
			{
				int tx = i + dx[k], ty = j + dy[k];
				if (tx >= 0 && tx < n && ty >= 0 && ty < m)
				{
					addEdge(id[i][j], id[tx][ty], 1);
				}
			}
		}
	}
	static int dist[M];
	shortestpath::go(s, dist, tot, G);

	int ans = 0;
	for (int i=1; i<=tot; ++i)
		ans = max(ans, dist[i]);
	printf("%d\n", ans-1);
	return 0;
}